package com.borya.filter.auth;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.borya.constant.RedisConstant;
import com.borya.constant.SystemConstant;
import com.borya.framework.util.ObjectUtils;
import com.borya.model.db.PackageInfo;
import com.borya.model.db.SdkPackageInfo;
import com.borya.model.db.User;
import com.borya.model.entity.HeaderEntity;
import com.borya.model.entity.UserToken;
import com.borya.statuscode.StatusCode;
import com.borya.userauth.UserAuthManager;
import com.borya.util.SystemConfig;
import com.borya.util.cipher.EncryptUtils;

/**
 * 判断用户和参数是否合法
 */
public class AuthHelper {

	private static Logger log = Logger.getLogger(AuthHelper.class);

	public static final int IOS = 1;
	public static final int ANDROID = 2;
	public static final int WEB = 3;

	public final static byte[] key = "ab8QI1waZxVqxQ2c".getBytes();

	/**
	 * 解密类型 hash 主键
	 */
	public static final String DECRYPT_MAP_KEY = "kameng:common:decrypt";

	public static AuthResponse auth(AuthRequest request) {
		if (request.getUrl().contains("ums/")) {
			return AuthFactory.getOperation("ums").apply(request);
		}
		AuthResponse authResponse = new AuthResponse();
		authResponse.setAccess(false);
		authResponse.setMsg(StatusCode.FORBID.toJSON());
		log.warn("The request is not for EAS, authRequest: " + request.toString());
		return authResponse;
	}

	public static String getSeparateChar(String md5) {
		char[] chars = md5.toCharArray();
		StringBuilder sb = new StringBuilder();
		int start = 0;
		for (int i = 0; i < chars.length; i++) {
			if (start < 2) {
				sb.append(chars[i]);
				start++;
			} else if (start == 2) {
				i = i + 1;
				start = 0;
			}
		}
		return sb.toString();
	}

	public static String getDivideChar(String md5) {
		char[] chars = md5.toCharArray();
		StringBuilder sb = new StringBuilder();
		for (char aChar : chars) {
			sb.append(aChar % 10);
		}
		return sb.toString();
	}

	/**
	 * 通过apptype获取包名
	 *
	 * @param appType
	 * @return
	 */
	public static String getPackageName(String appType, String defaultPackageName) {
		if (Objects.equals(AppType.KA_MENG.getType(), appType)) {
			return AppType.KA_MENG.getPackageName();
		} else if (Objects.equals(AppType.XI_NIU.getType(), appType)) {
			return AppType.XI_NIU.getPackageName();
		} else if (Objects.equals("3", appType)) {
			return AppType.YI_JIA.getPackageName(); // FIXME: 2019/5/17
													// 特殊处理，没有appType为3的情况
		} else if (Objects.equals(AppType.BEIDOU_GUOXING.getType(), appType)) {
			return AppType.BEIDOU_GUOXING.getPackageName();// 北斗国星
		} else if (Objects.equals(AppType.YI_JIA.getType(), appType)) {
			return AppType.YI_JIA.getPackageName();
		} else if (Objects.equals(AppType.QUAN_WANG_TONG.getType(), appType)) {
			return AppType.QUAN_WANG_TONG.getPackageName();
		} else if (Objects.equals(AppType.JU_LIAN.getType(), appType)) {
			return AppType.JU_LIAN.getPackageName();
		} else if (Objects.equals(AppType.KM_SDK.getType(), appType)) {
			// 卡盟SDK的APPID，APPKey都存在token内，需要先解密，故而使用body中的包名，待解密后再验证包名合法性
			return defaultPackageName;
		} else {
			return "";
		}
	}

	/**
	 * 解密token（兼容IOS新老版本） // FIXME: 2019/5/24 未来版本可以删除，采用新的解密方式
	 *
	 * @param authHeader
	 * @param token
	 * @param timestamp
	 * @param userId
	 * @param packageName
	 * @return
	 */
	public String getDecryptToken(HeaderEntity authHeader, String token, long timestamp, String userId,
			String packageName) {
		SystemConfig instance = SystemConfig.getInstance();
		String decryptToken;
		if (Objects.equals(AppType.KA_MENG.getType(), authHeader.getAppType())) { // 卡盟
			decryptToken = EncryptUtils.decryptNew(userId, timestamp, packageName, token);
		} else if (Objects.equals(AppType.XI_NIU.getType(), authHeader.getAppType())) { // 喜牛
			decryptToken = getTokenDiffOs(userId, timestamp, packageName, token,
					instance.getInteger(AppSignTokenVersion.XI_NIU_ANDROID.getToken()),
					instance.getInteger(AppSignTokenVersion.XI_NIU_IOS.getToken()), authHeader);
		} else if (Objects.equals(AppType.YI_JIA.getType(), authHeader.getAppType())) { // 亿嘉
			decryptToken = getTokenDiffOs(userId, timestamp, packageName, token,
					instance.getInteger(AppSignTokenVersion.YI_JIA_ANDROID.getToken()),
					instance.getInteger(AppSignTokenVersion.YI_JIA_IOS.getToken()), authHeader);
		} else if (Objects.equals(AppType.QUAN_WANG_TONG.getType(), authHeader.getAppType())) { // 全通
			decryptToken = getTokenDiffOs(userId, timestamp, packageName, token,
					instance.getInteger(AppSignTokenVersion.QUAN_WANG_TONG_ANDROID.getToken()),
					instance.getInteger(AppSignTokenVersion.QUAN_WANG_TONG_IOS.getToken()), authHeader);
		} else if (Objects.equals(AppType.JU_LIAN.getType(), authHeader.getAppType())) { // 聚联
			decryptToken = getTokenDiffOs(userId, timestamp, packageName, token,
					instance.getInteger(AppSignTokenVersion.JU_LIAN_ANDROID.getToken()),
					instance.getInteger(AppSignTokenVersion.JU_LIAN_IOS.getToken()), authHeader);
		} else if (Objects.equals(AppType.KM_SDK.getType(), authHeader.getAppType())) {
			decryptToken = EncryptUtils.decryptNew(userId, timestamp, packageName, token);
		} else {
			decryptToken = EncryptUtils.decrypt(userId, timestamp, packageName, token);
		}
		return decryptToken;
	}

	/**
	 * 根据os的版本区分解密方式
	 *
	 * @param userId
	 *            用户ID
	 * @param timestamp
	 *            时间戳
	 * @param packageName
	 *            包名
	 * @param token
	 *            token
	 * @param androidTokenVersion
	 *            安卓token版本
	 * @param iosTokenVersion
	 *            苹果token版本
	 * @return
	 */
	private String getTokenDiffOs(String userId, long timestamp, String packageName, String token,
			int androidTokenVersion, int iosTokenVersion, HeaderEntity authHeader) {
		String decryptToken;
		if (OsType.ANDROID.getType() == authHeader.getOsType() && authHeader.getAppVersion() >= androidTokenVersion) {
			decryptToken = EncryptUtils.decryptNew(userId, timestamp, packageName, token);
		} else if (OsType.IOS.getType() == authHeader.getOsType() && authHeader.getAppVersion() >= iosTokenVersion) {
			decryptToken = EncryptUtils.decryptNew(userId, timestamp, packageName, token);
		} else {
			decryptToken = EncryptUtils.decrypt(userId, timestamp, packageName, token);
		}
		return decryptToken;
	}

	/**
	 * 构造HeaderEntity
	 *
	 * @param authParams
	 * @return
	 */
	public HeaderEntity getHeaderEntity(List<String> authParams) {
		HeaderEntity authHeader = new HeaderEntity();
		authHeader.setUserId(authParams.get(0));
		authHeader.setAppVersion(Integer.valueOf(authParams.get(1)));
		authHeader.setOsVersion(authParams.get(2));
		authHeader.setOsType(Integer.valueOf(authParams.get(3)));
		authHeader.setAppType(authParams.get(4));
		return authHeader;
	}

	/**
	 * 构造userToken
	 *
	 * @param url
	 * @param host
	 * @param tokens
	 * @return
	 */
	public UserToken getUserToken(String url, String host, String[] tokens) {
		UserToken ut = new UserToken();
		ut.setUrl(url);
		ut.setHost(host);
		ut.setAppVersion(tokens[0]);
		ut.setOsVersion(tokens[1]);
		ut.setOsType(tokens[2]);
		ut.setPhoneType(tokens[3]);
		ut.setNet(tokens[4]);
		ut.setTmsi(tokens[5]);
		if (ObjectUtils.nonNullOrEmpty(tokens[6]) && ObjectUtils.nonNullOrEmpty(tokens[4])
				&& ObjectUtils.nonEqual("Unable", tokens[4])) {
			ut.setHost(tokens[6]);
		}
		ut.setLongitude(tokens[7]);
		ut.setLatitude(tokens[8]);
		final String imei = tokens.length > 9 ? tokens[9] : "";
		final String locationFlag = tokens.length > 10 ? tokens[10].trim() : String.valueOf(User.LocationFlag.CLOSE);
		// 图片水印
		final String waterAddress = tokens.length > 11 ? tokens[11].trim() : "";
		final String waterInfo = tokens.length > 12 ? tokens[12].trim() : "";
		String crc32 = tokens.length > 13 ? tokens[13].trim() : "";
		final String hookFlag = tokens.length > 14 ? tokens[14].trim() : "";
		final String appId = tokens.length > 16 ? tokens[16].trim() : "";
		final String appKey = tokens.length > 17 ? tokens[17].trim() : "";
		final String appSign = tokens.length > 18 ? tokens[18].trim() : "";
		ut.setImei(imei);
		ut.setLocationFlag(locationFlag);
		ut.setWaterAddress(waterAddress);
		ut.setWaterInfo(waterInfo);
		ut.setCrc32(crc32);
		ut.setHookFlag(hookFlag);
		ut.setAppId(appId);
		ut.setAppKey(appKey);
		ut.setSign(appSign);
		return ut;
	}

	/**
	 * 校验crc32 是否一致
	 *
	 * @param url
	 * @param authHeader
	 * @param token
	 * @param ut
	 */
	public void checkCrc32(String url, HeaderEntity authHeader, String token, UserToken ut) {
		if (StringUtils.isNotEmpty(ut.getCrc32())
				|| !Objects.equals(AppType.KM_SDK.getType(), authHeader.getAppType())) {
			String packageName = AuthHelper.getPackageName(authHeader.getAppType(), null);
			String jsonStr = UserAuthManager.getInstance().redis_hget("ka_meng:androdpackage",
					packageName + ut.getAppVersion());
			if (StringUtils.isEmpty(jsonStr)) {
				log.warn("未查询到版本号");
			} else {
				PackageInfo packageInfo = JSON.parseObject(jsonStr, PackageInfo.class);
				if (Objects.nonNull(packageInfo)) {
					log.warn("host:" + ut.getHost() + ", packageInfo: " + packageInfo.toString());
					if (StringUtils.isNotEmpty(packageInfo.getCrc32())) {
						List<String> crc32List = Arrays.stream(packageInfo.getCrc32().split(","))
								.collect(Collectors.toList());
						log.warn("Request crc32：" + ut.getCrc32() + "。dataBase crc32：" + packageInfo.getCrc32());
						if (!crc32List.contains(ut.getCrc32())) {
							log.warn("[" + token + "] Illegal token,tokne=[" + token + "],url=" + url);
							throw new IllegalStateException("crc32不一致");
						}
						if (crc32List.size() > 1) {
							log.warn("可能是特殊机型:token=[" + token + "],url=" + url);
						}
					} else {
						log.warn("host:" + ut.getHost() + ", can not find crc32");
					}
				}
			}
		}
	}

	public void checkHookFlag(AuthRequest authRequest, UserToken ut) {
		if (OsType.ANDROID.getType() != authRequest.getOsType())
			return;
		boolean filter = AppHookFlagVersion.hasAbility(authRequest.getAppType(), authRequest.getAppVersion());
		if (filter) {
			if (StringUtils.isEmpty(ut.getHookFlag())) {
				log.warn(String.format("请求IP：%s，当前请求不包含hookFlag", authRequest.getHost()));
				throw new IllegalStateException("参数错误");
			}
			if (!StringUtils.isNumeric(ut.getHookFlag())) {
				log.warn(String.format("请求IP：%s，当前请求hookFlag值不是数字，非法请求! hookFlag: %s", authRequest.getHost(),
						ut.getHookFlag()));
				throw new IllegalStateException("参数错误");
			}
		} else {
			ut.setHookFlag("0");
		}
	}

	public void checkSdkInfo(AuthRequest authRequest, UserToken ut, JSONObject object, String packageName) {
		if (authRequest.getUrl().contains(SystemConstant.Sdk.API_PATH)) {
			if (StringUtils.equals(AppType.KM_SDK.getType(), authRequest.getAppType())) {
				if (TextUtils.isBlank(ut.getAppId()) || TextUtils.isBlank(ut.getAppKey())) {
					log.warn(String.format("请求IP：%s，当前请求AppId或AppKey有空值，非法请求! appId: %s, appKey: %s",
							authRequest.getHost(), ut.getAppId(), ut.getAppKey()));
					throw new IllegalStateException("参数错误");
				}
				String jsonStr = UserAuthManager.getInstance().redis_hget(RedisConstant.SDK_PACKAGES, ut.getAppId());
				if (TextUtils.isBlank(jsonStr)) {
					log.warn(String.format("请求IP：%s，当前请求AppId找不到对应包信息，非法请求! appId: %s, appKey: %s",
							authRequest.getHost(), ut.getAppId(), ut.getAppKey()));
					throw new IllegalStateException("参数错误");
				}
				SdkPackageInfo info = JSON.parseObject(jsonStr, SdkPackageInfo.class);
				if (Objects.nonNull(info)) {
					if (!StringUtils.equals(info.getAppKey(), ut.getAppKey())) {
						log.warn(String.format("请求IP：%s，当前请求AppId和AppKey不匹配，非法请求! appId: %s, appKey: %s",
								authRequest.getHost(), ut.getAppId(), ut.getAppKey()));
						throw new IllegalStateException("参数错误");
					}
					if (!StringUtils.equals(info.getPackageName(), packageName)) {
						log.warn(String.format("请求IP：%s，当前请求packageName和AppId对应的不一致，非法请求! appId: %s, packageName: %s",
								authRequest.getHost(), ut.getAppId(), packageName));
						throw new IllegalStateException("参数错误");
					}
					if (!StringUtils.equals(info.getPackageSign(), ut.getSign())) {
						log.warn(String.format("请求IP：%s，当前请求packageSign和AppId对应的不一致，非法请求! appId: %s, packageSign: %s",
								authRequest.getHost(), ut.getAppId(), ut.getSign()));
						throw new IllegalStateException("参数错误");
					}
					long version;
					try {
						version = Long.valueOf(ut.getAppVersion());
					} catch (NumberFormatException e) {
						version = 0L;
					}
					if (info.getMinRunVersion() > version) {
						log.warn(String.format("请求IP：%s，当前SDK版本低于最低可运行版本! appId: %s, version: %s",
								authRequest.getHost(), ut.getAppId(), ut.getAppVersion()));
						throw new IllegalStateException("参数错误");
					}
					object.put(SystemConstant.Sdk.JsonKeys.JSON_KEY_DETAIL_TYPE, info.getDetailType());
					object.put(SystemConstant.Sdk.JsonKeys.JSON_KEY_DEALER_ID, info.getDealerId());
					object.put(SystemConstant.Sdk.JsonKeys.JSON_KEY_DEALER_NAME, info.getDealerName());
					object.put(SystemConstant.Sdk.JsonKeys.JSON_KEY_POP_CHANNEL, info.getPopChannel());
					object.put(SystemConstant.Sdk.JsonKeys.JSON_KEY_POP_CHANNEL_NAME, info.getPopChannelName());
				}
			} else {
				log.warn(String.format("请求IP：%s，当前请求路径和AppType不匹配! appType: %s", authRequest.getHost(),
						authRequest.getAppType()));
				throw new IllegalStateException("参数错误");
			}
		}
	}

	/**
	 * 构造AuthRequest
	 *
	 * @param url
	 * @param host
	 * @param body
	 * @param authParams
	 * @return
	 */
	public AuthRequest getAuthRequest(String url, String host, String body, List<String> authParams) {
		AuthRequest authRequest = new AuthRequest();
		authRequest.setUserId(authParams.get(0));
		authRequest.setAppVersion(Integer.valueOf(authParams.get(1)));
		authRequest.setOsVersion(authParams.get(2));
		authRequest.setOsType(Integer.valueOf(authParams.get(3)));
		authRequest.setAppType(authParams.get(4));
		if (authParams.size() >= 6) {
			authRequest.setSign(authParams.get(5));
		}
		authRequest.setHost(host);
		authRequest.setBody(body);
		authRequest.setUrl(url);
		return authRequest;
	}

}
